﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace TestChemicalEquilibrium
{
    public partial class FormDiagram : Form
    {
        public delegate int GetDataCallback();

        public class Data
        {
            public string Name;
            public Color Color;
            public Rectangle Rectangle;
            public GetDataCallback GetDataCallback;
            public Queue<int> Datas = new Queue<int>();

            int MaxData = 100;
            int MinData = 0;
            int ZeroData = 0;

            public Data(string name, Color color, Rectangle rectangle, GetDataCallback getData)
            {
                this.Name = name;
                this.Color = color;
                this.Rectangle = rectangle;
                this.GetDataCallback = getData;
                this.MaxData = rectangle.Height;
            }

            public void GetData()
            {
#if DEBUG
                int data = this.GetDataCallback();
                this.MaxData = Math.Max(this.MaxData, data);
                this.MinData = Math.Min(this.MinData, data);
                this.ZeroData = this.Rectangle.Top + this.MaxData * this.Rectangle.Height / (this.MaxData - this.MinData);
                this.Datas.Enqueue(data);
#endif
            }

            Point PointMouse = new Point();
            public void DrawData(Graphics G, Point pointMouse, bool bMouseDown)
            {
                if (this.Datas.Count > this.Rectangle.Width) this.Datas.Dequeue();

                Font font = new Font("宋体", 9f);

                G.DrawRectangle(Pens.Green, this.Rectangle);
                G.DrawLine(Pens.DarkRed, this.Rectangle.Left, ZeroData, this.Rectangle.Right, ZeroData);
                G.DrawString("0", font, Brushes.DarkRed, this.Rectangle.Right, ZeroData);
                int[] datas = this.Datas.ToArray();


                if (datas.Length > 0)
                {
                    Point p1 = new Point(Rectangle.Right - this.Datas.Count, this.Rectangle.Top + (this.MaxData - datas[0]) * this.Rectangle.Height / (this.MaxData - this.MinData));

                    for (int i = Rectangle.Right - this.Datas.Count; i < Rectangle.Right; i++)
                    {
                        Point p2 = new Point(i, this.Rectangle.Top + (this.MaxData - datas[i - Rectangle.Right + this.Datas.Count]) * this.Rectangle.Height / (this.MaxData - this.MinData));

                        G.DrawLine(new Pen(this.Color), p1, p2);

                        p1 = p2;
                    }

                    string str = string.Format("{0}  = {1}, Max = {2}, Min = {3}", this.Name, datas[datas.Length - 1], this.MaxData, this.MinData);
                    G.DrawString(str, font, new SolidBrush(this.Color), new RectangleF(p1, G.MeasureString(str, font)));

                    if (bMouseDown)
                        this.PointMouse.X--;
                    else
                        this.PointMouse = pointMouse;

                    if (this.PointMouse.X >= this.Rectangle.Right - this.Datas.Count
                        && this.PointMouse.X < this.Rectangle.Right)
                    {
                        Point mouse = new Point(this.PointMouse.X, this.Rectangle.Top + (this.MaxData - datas[this.PointMouse.X - Rectangle.Right + this.Datas.Count]) * this.Rectangle.Height / (this.MaxData - this.MinData) - 1);
                        G.DrawLine(Pens.DarkSeaGreen, this.Rectangle.Left, mouse.Y, this.Rectangle.Right, mouse.Y);
                        G.DrawLine(Pens.DarkSeaGreen, mouse.X, this.Rectangle.Top, mouse.X, this.Rectangle.Bottom);

                        G.DrawString(datas[this.PointMouse.X - Rectangle.Right + this.Datas.Count].ToString(), font, Brushes.DarkSeaGreen, mouse);
                    }
                }
            }
        }

        Data[] Datas;

        Timer Timer = new Timer();

        public FormDiagram(params Data[] datas)
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);

            this.Datas = datas;

            InitializeComponent();

            Timer.Interval = 50;
            Timer.Tick += new EventHandler(Timer_Tick);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            Timer.Start();
        }

        Point pointMouse = new Point();
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (!bMouseDown) pointMouse = e.Location;
        }

        bool bMouseDown = false;
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            bMouseDown = true;
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            bMouseDown = false;
        }

        void Timer_Tick(object sender, EventArgs e)
        {
            foreach (Data data in this.Datas)
            {
                data.GetData();
            }

            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics G = e.Graphics;

            foreach (Data data in this.Datas)
            {
                data.DrawData(G, pointMouse, bMouseDown);
            }
        }
    }
}
